<?php

require_once ROOT_LIBRARY . DS . 'utils.php';
require_once ROOT_LIBRARY_LAZADA . DS . 'global_vars.php';

class delivery_promises {

    const RULE_RESULT_TYPE_SET_TAGET_TIME = 1;
    const RULE_RESULT_TYPE_AMOUNT_OF_TIME = 2;
    const RULE_RESULT_TYPE_ADD_TAGET_TIME = 3;
    const RULE_RESULT_TYPE_ADD_STOP_TIME = 4;

    private $_cache;

    /**
     *
     * @var oms
     */
    private $_oms;
    private $_rule_model;
    private $_location_model;

    function __construct($cache, $oms, $location_model, $rule_model) {
        $this->_cache = $cache;
        $this->_oms = $oms;
        $this->_rule_model = $rule_model;
        $this->_location_model = $location_model;
    }

    public function process_rules($sku, $location, $date) {
        $rules = $this->_rule_model->get_all();
        $stock = $this->_oms->get_stock($sku);
        
        $time_max = $time_min = 0;
        $type = self::RULE_RESULT_TYPE_AMOUNT_OF_TIME;
        $log = "[{$sku}][{$location}][STOCK={$stock}] -> ";
        foreach ($rules as $rule) {

            $rule_condition = $this->check_condition($sku, $stock, $location, $date, $rule);
            if ($rule_condition) {
                $log .= "[{$rule['comment']}][{$rule['action']}]";

                $res = $this->evaluate($location, $rule);
                
                if (isset($res['rule_stop']) && $res['rule_stop'] == 1) {
                    $time_max += (int)$res['result_max'];
                    $time_min += (int)$res['result_min'];
                    $type = self::RULE_RESULT_TYPE_ADD_STOP_TIME;
                    break;
                } else if ($res['result_type'] == self::RULE_RESULT_TYPE_AMOUNT_OF_TIME){
                    $time_max += (int)$res['result_max'];
                    $time_min += (int)$res['result_min'];
                }else if ($res['result_type'] == self::RULE_RESULT_TYPE_SET_TAGET_TIME) {
                    $time_max = $res['result_max'];
                    $time_min = $res['result_min'];
                    $type = self::RULE_RESULT_TYPE_SET_TAGET_TIME;
                    break;
                } else if ($res['result_type'] == self::RULE_RESULT_TYPE_ADD_TAGET_TIME) {
                    $time_max += (int)$res['result_max'];
                    $time_min += (int)$res['result_min'];
                    $type = self::RULE_RESULT_TYPE_ADD_TAGET_TIME;
                    break;
                }
            }
        }
        
        utils::log($log);
        $gvars = global_vars::instance();
        if ($gvars->get('debug')) {
            $gvars->set("rule_{$sku}_{$location}", $log);
        }

        $result = array(
            'result_type' => $type,
            'result_max' => $time_max,
            'result_min' => $time_min,
            'text_display' => $res['text_display']
        );
        return $result;
    }

    public function check_condition($sku, $stock, $location, $date, $rule) {

        if ($rule['conditions'] == null)
            return true;

        $arr_conditions = json_decode($rule['conditions'], true);
        $result = true;

        foreach ($arr_conditions as $condition) {
            switch ($condition['type']) {
                case "RULE_CONDITION_STOCK":
                    $result = $result && utils::invokeOperator($stock, $condition['operator'], $condition['params']);
                    break;
                case "RULE_CONDITION_LOCATION":
                    $result = $result && utils::invokeOperator($location, $condition['operator'], $condition['params']);
                    break;
                case "RULE_CONDITION_SKU":
                    $result = $result && utils::invokeOperator($sku, $condition['operator'], $condition['params']);
                    break;
                case "RULE_CONDITION_DATE":
                    $result = $result && utils::invokeDateOperator($date, $condition['operator'], $condition['params']);
                    break;
            }
        }

        return $result;
    }

    public function evaluate($location, $rule) {
        $action = json_decode($rule['action']);
        $time_max = $time_min = 0;
        $rule_stop = 0;
        $offset = isset($action->offset) ? $action->offset : 0;
        $type = self::RULE_RESULT_TYPE_AMOUNT_OF_TIME;
        
        switch ($action->type) {
            case 'RULE_ACTION_GET_LOCATION_TIME':
                $time_max = $time_min = $this->_location_model->get_province_time($location);
                break;
            case 'RULE_ACTION_GET_SUPLIER_LEAD_TIME':
            case 'RULE_ACTION_ADD_TIME':
                $time_max = (int)$action->value + (int)$offset;
                $time_min = $action->value;
                break;
            case 'RULE_ACTION_SET_TARGET_TIME':
                $time_max = $time_min = $action->value;       
                $type = self::RULE_RESULT_TYPE_SET_TAGET_TIME;
                break;
            case 'RULE_ACTION_ADD_TARGET_TIME':
                $time_max = (int)$action->value + (int)$offset;
                $time_min = $action->value;
                $type = self::RULE_RESULT_TYPE_ADD_TAGET_TIME;
                break;
        }

        if (isset($action->rule_stop) && $action->rule_stop == 1 && $type !== self::RULE_RESULT_TYPE_SET_TAGET_TIME) {
            $type = self::RULE_RESULT_TYPE_ADD_STOP_TIME;
            $rule_stop = 1;
        }
        
        return array(
            'result_type' => $type,
            'result_max' => $time_max,
            'result_min' => $time_min,
            'rule_stop' => $rule_stop,
            'text_display' => isset($action->text_display) ? $action->text_display : ''
        );
    }

    public function get_time($sku, $location, $date) {

        $result = $this->_cache->cache('shipping_time_' . $sku . "_" . $location);
        if ($result)
            return $result;

        $result = $this->process_rules($sku, $location, $date);
        $this->_cache->cache('shipping_time_' . $sku . "_" . $location, $result);
        return $result;
    }

    public function get_time_all_location($sku, $date) {

        $results = $this->_cache->cache('st_all_location_' . $sku);
        if ($results)
            return $results;
        
        $results = array();
        $locations = $this->_location_model->get_all();

        foreach ($locations as $location) {
            $results[] = array(
                'location' => $location['name'],
                'result' => $this->get_time($sku, $location['code'], $date)
            );
        }
        $this->_cache->cache('st_all_location_' . $sku, $results);
        return $results;
    }

}

?>
